#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <string.h>
#include <errno.h>
#include <ctype.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

#define SIZE 512 
#define ZERO '\0'
#define SEP " "
#define NUM 32
#define SkipPath(p) do{ p+=(strlen(p)-1); while(*p!='/') p--; }while(0)

#define SkipSpace(cmd, pos) do{\
  while(1){\
    if(isspace(cmd[pos]))\
    pos++;\
    else break;\
  }\
}while(0)

// "ls -a -l -n > myfile.txt"
#define NONE_REDIR 0
#define IN_REDIR   1
#define OUT_REDIR  2
#define APP_REDIR  3

int redir_type = NONE_REDIR;
char *filename = NULL;


char cwd[SIZE*2];
char * gArgv[NUM];
int lastcode=0;


// getusername

const char* GetUserName()
{
  const char* name=getenv("USER");
  if(name==NULL) return "none";
  return name;
}
//gethostname

const char* GetHostName()
{
  const char* hostname=getenv("HOSTNAME");
  if(hostname==NULL) return "NONE";
  return hostname;
}
//getcwd

const char* GetCwd()
{
  const char* cwd=getenv("PWD");
  if(cwd==NULL) return"NONE";
  return cwd;
}

void MakeCommamdLineAndPrint()
{
  char line[SIZE];
  const char* username=GetUserName();
  const char* hostname=GetHostName();
  const char* cwd=GetCwd();

  SkipPath(cwd);
  snprintf(line,sizeof(line),"[%s@%s %s]: ",username,hostname, strlen(cwd)==1 ? "/" : cwd+1);
  printf("%s",line);
  fflush(stdout);
}
 int GetuserCommand(char command[],size_t n)
{
  char * s=fgets(command,n,stdin);
  if(s==NULL) return -1;
  command[strlen(command)-1]=ZERO;
  return strlen(command);
}

void SplitCommand(char command[],size_t n)
{
  (void)n;
  //"ls -a -l -n" -> "ls" "-a" "-l" "-n"
  gArgv[0]=strtok(command,SEP); 
  int idex=1;
  while((gArgv[idex++]=strtok(NULL,SEP)));
}

void Die()
{
  exit(1);
}

void  ExecuteCommand()
{  
  pid_t id=fork();
  if(id<0) Die();
  else if(id==0)
  {
    // 重定向设置
    if(filename != NULL)
    {
      if(redir_type == IN_REDIR)
      {
        int fd =open(filename, O_RDONLY);
        dup2(fd, 0);
      }
      else if(redir_type == OUT_REDIR)
      {
        int fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0666);
        dup2(fd, 1);
      }
      else if(redir_type == APP_REDIR)
      { 
        int fd = open(filename, O_WRONLY | O_CREAT | O_APPEND, 0666);
        dup2(fd, 1); 
      }
      else 
      { 
      }
    }
    //child
    execvp(gArgv[0],gArgv);
    exit(errno);
  }
  else
  {
    // father
    int status=0;
    pid_t rid=waitpid(id,&status,0);
    if(rid>0)
    {
      lastcode=WEXITSTATUS(status);
      if(lastcode!=0) printf("%s:%s:%d\n",gArgv[0],strerror(lastcode),lastcode);
    }
  }
}

const char* GetHome()
{
  const char * home=getenv("Home");
  if(home) return "/root";
  return home;
}

void Cd()
{
  const char * path=gArgv[1];
  if(path==NULL) path=GetHome();

  //path一定存在
  chdir(path);

  // 刷新环境变量
  char temp[SIZE*2];
  getcwd(temp,sizeof(temp));
  snprintf(cwd,sizeof(cwd),"PWD=%s",temp);
  putenv(cwd);
}  

int CheckBuild()
{
  int yes=0;
  const char * enter_cmd=gArgv[0];
  if(strcmp(enter_cmd,"cd")==0)
  {
    yes=1;
    Cd();
  }
  else if(strcmp(enter_cmd,"echo")==0 && strcmp(gArgv[1],"$?")==0)
  {
    yes=1;
    printf("%d\n",lastcode);
    lastcode=0;
  }
  return yes;
}

void CheckRedir(char cmd[])
{
  // > >> <
  // "ls -a -l -n > myfile.txt"
  int pos = 0;
  int end = strlen(cmd);
  while(pos < end)
  {
    if(cmd[pos] == '>')
    {
      if(cmd[pos+1] == '>')
      {
        cmd[pos++] = 0;
        pos++;
        redir_type = APP_REDIR;
        SkipSpace(cmd, pos);
        filename = cmd + pos;
      }
      else
      {
        cmd[pos++] = 0;
        redir_type = OUT_REDIR;
        SkipSpace(cmd, pos);
        filename = cmd + pos;
      }

    }
    else if(cmd[pos] == '<')
    {
      cmd[pos] = 0;
      redir_type = IN_REDIR;
      SkipSpace(cmd, pos);
      filename = cmd + pos;
    }
    else
    {
      pos++;
    }
  }
}

int main()
{

  int quit=0;
  while(!quit)
  {
    redir_type = NONE_REDIR;
    filename = NULL;
    //printf("name: %s\n",GetUserName());
  
    // 1.输出一个命令行
    MakeCommamdLineAndPrint();

    // 2.获取用户命令字符串
    char usercommand[SIZE];
    int n=GetuserCommand(usercommand,sizeof(usercommand));
    if(n<=0) return 1;
    
    // 2.1.checkredir
    CheckRedir(usercommand);  

// // 2.2.debug
// printf("cmd: %s\n",usercommand);
// printf("redir: %d\n",redir_type);
// printf("filename: %s\n",filename);

   // 3.命令行字符串分割
   SplitCommand(usercommand,sizeof(usercommand));

   // 4.检查是否是内建命令
   n=CheckBuild();
   if(n) continue;

   // 5.执行代码
   ExecuteCommand();

  }

  return 0;
}




















